package com.ikingtech.platform.service.datasource.service;

import com.alibaba.druid.pool.DruidDataSource;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.datasource.model.enums.DatasourceSchemaTypeEnum;
import com.ikingtech.platform.service.datasource.entity.DatasourceDO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author tie yan
 */
@Slf4j
public class DatasourceExecutor {

    private final Map<String, DataSource> dataSourceMap = new HashMap<>();

    /**
     * 执行SQL语句并返回结果集
     * @param entity 数据源对象
     * @param sql SQL语句
     * @return 结果集
     */
    public List<Map<String, Object>> execute(DatasourceDO entity, String sql) {
        // 根据数据源类型和连接信息执行SQL语句
        return this.execute(DatasourceSchemaTypeEnum.valueOf(entity.getType()), entity.getJdbcUrl(), entity.getUsername(), entity.getPassword(), sql);
    }

    /**
     * 执行SQL语句并返回结果集
     *
     * @param type 数据源类型
     * @param jdbcUrl 数据库连接URL
     * @param username 数据库用户名
     * @param password 数据库密码
     * @param sql SQL语句
     * @return 结果集
     */
    public List<Map<String, Object>> execute(DatasourceSchemaTypeEnum type, String jdbcUrl, String username, String password, String sql) {
        List<Map<String, Object>> result = new ArrayList<>();
        DataSource dataSource = this.dataSourceMap.get(jdbcUrl);
        if (null == dataSource) {
            dataSource = this.createDatasource(type, jdbcUrl, username, password);
            this.dataSourceMap.put(jdbcUrl, dataSource);
        }
        try (Connection connection = dataSource.getConnection()) {
            Statement statement = connection.createStatement();
            ResultSet executeResult = statement.executeQuery(sql);
            ResultSetMetaData resultMetaData = executeResult.getMetaData();
            while (executeResult.next()) {
                Map<String, Object> columnResult = new HashMap<>();
                for (int i = 1; i <= resultMetaData.getColumnCount(); i++) {
                    columnResult.put(resultMetaData.getColumnName(i), executeResult.getObject(i));
                }
                result.add(columnResult);
            }
            statement.close();
            return result;
        } catch (Exception e) {
            log.error("service-datasource error: {}", ExceptionUtils.getStackTrace(e));
            throw new FrameworkException("datasourceExecuteException");
        }
    }

    /**
     * 创建数据源
     * @param databaseType 数据库类型
     * @param jdbcUrl 数据库连接地址
     * @param username 数据库用户名
     * @param password 数据库密码
     * @return 数据源对象
     */
    private DataSource createDatasource(DatasourceSchemaTypeEnum databaseType, String jdbcUrl, String username, String password) {
        try (DruidDataSource datasource = new DruidDataSource()) {
            // 设置数据库驱动类名
            datasource.setDriverClassName(databaseType.driverClassName);
            // 设置数据库连接地址
            datasource.setUrl(jdbcUrl);
            // 设置数据库用户名
            datasource.setUsername(username);
            // 设置数据库密码
            datasource.setPassword(password);
            // 设置获取连接失败后是否中断
            datasource.setBreakAfterAcquireFailure(true);
            return datasource;
        } catch (Exception e) {
            // 抛出异常
            throw new FrameworkException("datasourceCreateFail");
        }
    }

}
